﻿// -----------------------------------------------------------------------
// <copyright file="PushRequestDetailRepository.cs" company="Zen Design Corp">
// TODO: Update copyright text.
// </copyright>
// -----------------------------------------------------------------------

namespace Zen.BlackBerry.Push.Repositories
{
	using System;
	using System.Collections.Generic;
	using System.Linq;
	using Zen.BlackBerry.Common;
	using Zen.BlackBerry.Configuration;
	using Zen.BlackBerry.Pap;
	using Zen.BlackBerry.Push.DataAccess;
	using Zen.BlackBerry.Push.Request;
	using Zen.BlackBerry.Subscription;
	//using Zen.Data.Extensions;

	/// <summary>
	/// TODO: Update summary.
	/// </summary>
	public class PushRequestDetailRepository : Repository, IPushRequestDetailRepository
	{
		private IPushProperties _pushProperties;

		public PushRequestDetailRepository(IPushProperties pushProperties)
		{
			_pushProperties = pushProperties;
		}

		private void UpdatePushRequestDetailCore(PushRequestDetail pushRequestDetail, bool allAddresses)
		{
			IQueryable<DbPushRequestDetail> query = ObjectContext
				.DbPushRequestDetails
				.Include("Request")
				.Where((item) => item.Request.PushId == pushRequestDetail.Id);
			if (!allAddresses)
			{
				query = query.Where((item) => item.Address == pushRequestDetail.Address);
			}

			foreach (var dbDetail in query)
			{
				dbDetail.MessageState = (short)pushRequestDetail.MessageState;
				dbDetail.StatusCode = pushRequestDetail.StatusCode.Code;
				dbDetail.StatusDescription = pushRequestDetail.StatusDescription;
				dbDetail.SenderName = pushRequestDetail.SenderName;
				dbDetail.SenderAddress = pushRequestDetail.SenderAddress;
				dbDetail.CompletedDate = pushRequestDetail.CompletedDate;
				dbDetail.LastUpdatedDate = DateTime.UtcNow;
			}
		}

		#region IPushRequestDetailRepository Members

		public void AddPushRequestDetail(PushRequestDetail pushRequestDetail)
		{
			DbPushRequest dbRequest = ObjectContext.DbPushRequests
				.First((item) => item.PushId == pushRequestDetail.Id);
			DbPushRequestDetail dbDetail =
				new DbPushRequestDetail
				{
					PushRequestDetailId = Guid.NewGuid(),
					Request = dbRequest,
					Address = pushRequestDetail.Address,
					CompletedDate = pushRequestDetail.CompletedDate,
					CreatedDate = DateTime.UtcNow,
					LastUpdatedDate = DateTime.UtcNow,
					MessageState = (short)pushRequestDetail.MessageState,
					SenderAddress = pushRequestDetail.SenderAddress,
					SenderName = pushRequestDetail.SenderName,
					StatusCode = pushRequestDetail.StatusCode.Code,
					StatusDescription = pushRequestDetail.StatusDescription,
					SubscriberId = pushRequestDetail.SubscriberId
				};
			ObjectContext.DbPushRequestDetails.Add(dbDetail);
			ObjectContext.SaveChanges();
		}

		public void AddPushRequestDetails(IEnumerable<PushRequestDetail> pushRequestDetails)
		{
			foreach (var pushRequestDetail in pushRequestDetails)
			{
				DbPushRequest dbRequest = ObjectContext.DbPushRequests
					.First((item) => item.PushId == pushRequestDetail.Id);
				DbPushRequestDetail dbDetail =
					new DbPushRequestDetail
					{
						PushRequestDetailId = Guid.NewGuid(),
						Request = dbRequest,
						Address = pushRequestDetail.Address,
						CompletedDate = pushRequestDetail.CompletedDate,
						CreatedDate = DateTime.UtcNow,
						LastUpdatedDate = DateTime.UtcNow,
						MessageState = (short)pushRequestDetail.MessageState,
						SenderAddress = pushRequestDetail.SenderAddress,
						SenderName = pushRequestDetail.SenderName,
						StatusCode = pushRequestDetail.StatusCode.Code,
						StatusDescription = pushRequestDetail.StatusDescription,
						SubscriberId = pushRequestDetail.SubscriberId
					};
				ObjectContext.DbPushRequestDetails.Add(dbDetail);
			}
			ObjectContext.SaveChanges();
		}

		public IEnumerable<PushRequestDetail> FindByDateRange(DateTime fromDate, DateTime toDate, int startIndex, int endIndex)
		{
			return ObjectContext.DbPushRequestDetails
				.Include("Request")
				.Where((item) => item.CreatedDate >= fromDate && item.CreatedDate <= toDate)
				.Skip(startIndex)
				.Take(endIndex - startIndex + 1)
				.Select((item) =>
					new PushRequestDetail
					{
						Id = item.Request.PushId,
						Address = item.Address,
						CompletedDate = item.CompletedDate,
						CreatedDate = item.CreatedDate,
						MessageState = (MessageState)item.MessageState,
						ModifiedDate = item.LastUpdatedDate,
						SenderAddress = item.SenderAddress,
						SenderName = item.SenderName,
						StatusCode = StatusCode.GetCode(item.StatusCode),
						StatusDescription = item.StatusDescription,
						SubscriberId = item.SubscriberId,
						SubscriberType = (SubscriberType)item.SubscriberType
					});
		}

		public IEnumerable<PushRequestDetail> FindById(string id)
		{
			return ObjectContext.DbPushRequestDetails
				.Include("Request")
				.Where((item) => item.Request.PushId == id)
				.Select((item) =>
					new PushRequestDetail
					{
						Id = item.Request.PushId,
						Address = item.Address,
						CompletedDate = item.CompletedDate,
						CreatedDate = item.CreatedDate,
						MessageState = (MessageState)item.MessageState,
						ModifiedDate = item.LastUpdatedDate,
						SenderAddress = item.SenderAddress,
						SenderName = item.SenderName,
						StatusCode = StatusCode.GetCode(item.StatusCode),
						StatusDescription = item.StatusDescription,
						SubscriberId = item.SubscriberId,
						SubscriberType = (SubscriberType)item.SubscriberType
					});
		}

		public PushRequestDetail FindByIdAndAddress(string id, string address)
		{
			return ObjectContext.DbPushRequestDetails
				.Include("Request")
				.Where((item) => item.Request.PushId == id && item.Address == address)
				.Select((item) =>
					new PushRequestDetail
					{
						Id = item.Request.PushId,
						Address = item.Address,
						CompletedDate = item.CompletedDate,
						CreatedDate = item.CreatedDate,
						MessageState = (MessageState)item.MessageState,
						ModifiedDate = item.LastUpdatedDate,
						SenderAddress = item.SenderAddress,
						SenderName = item.SenderName,
						StatusCode = StatusCode.GetCode(item.StatusCode),
						StatusDescription = item.StatusDescription,
						SubscriberId = item.SubscriberId,
						SubscriberType = (SubscriberType)item.SubscriberType
					})
				.FirstOrDefault();
		}

		public IEnumerable<PushRequestDetail> FindByIdAndAddresses(string id, IEnumerable<string> addresses)
		{
			return ObjectContext.DbPushRequestDetails
				.Include("Request")
				.Where((item) => item.Request.PushId == id)
				.ContainsEx((item) => item.Address, addresses)
				.Select((item) =>
					new PushRequestDetail
					{
						Id = item.Request.PushId,
						Address = item.Address,
						CompletedDate = item.CompletedDate,
						CreatedDate = item.CreatedDate,
						MessageState = (MessageState)item.MessageState,
						ModifiedDate = item.LastUpdatedDate,
						SenderAddress = item.SenderAddress,
						SenderName = item.SenderName,
						StatusCode = StatusCode.GetCode(item.StatusCode),
						StatusDescription = item.StatusDescription,
						SubscriberId = item.SubscriberId,
						SubscriberType = (SubscriberType)item.SubscriberType
					});
		}

		public IEnumerable<PushRequestDetail> FindByIdAndStates(string id, IEnumerable<MessageState> states)
		{
			short[] stateValues = states.Select((item) => (short)item).ToArray();
			return ObjectContext.DbPushRequestDetails
				.Include("Request")
				.Where((item) => item.Request.PushId == id)
				.ContainsEx((item) => item.MessageState, stateValues)
				.Select((item) =>
					new PushRequestDetail
					{
						Id = item.Request.PushId,
						Address = item.Address,
						CompletedDate = item.CompletedDate,
						CreatedDate = item.CreatedDate,
						MessageState = (MessageState)item.MessageState,
						ModifiedDate = item.LastUpdatedDate,
						SenderAddress = item.SenderAddress,
						SenderName = item.SenderName,
						StatusCode = StatusCode.GetCode(item.StatusCode),
						StatusDescription = item.StatusDescription,
						SubscriberId = item.SubscriberId,
						SubscriberType = (SubscriberType)item.SubscriberType
					});
		}

		public IEnumerable<PushRequestDetail> FindByIdAndStatusCode(string id, StatusCode statusCode)
		{
			return ObjectContext.DbPushRequestDetails
				.Include("Request")
				.Where((item) => item.Request.PushId == id && item.StatusCode == statusCode.Code)
				.Select((item) =>
					new PushRequestDetail
					{
						Id = item.Request.PushId,
						Address = item.Address,
						CompletedDate = item.CompletedDate,
						CreatedDate = item.CreatedDate,
						MessageState = (MessageState)item.MessageState,
						ModifiedDate = item.LastUpdatedDate,
						SenderAddress = item.SenderAddress,
						SenderName = item.SenderName,
						StatusCode = StatusCode.GetCode(item.StatusCode),
						StatusDescription = item.StatusDescription,
						SubscriberId = item.SubscriberId,
						SubscriberType = (SubscriberType)item.SubscriberType
					});
		}

		public IEnumerable<PushRequestDetail> FindByIdAndSubscriberIds(string id, IEnumerable<string> subscriberIds)
		{
			return ObjectContext.DbPushRequestDetails
				.Include("Request")
				.Where((item) => item.Request.PushId == id)
				.ContainsEx((item) => item.SubscriberId, subscriberIds)
				.Select((item) =>
					new PushRequestDetail
					{
						Id = item.Request.PushId,
						Address = item.Address,
						CompletedDate = item.CompletedDate,
						CreatedDate = item.CreatedDate,
						MessageState = (MessageState)item.MessageState,
						ModifiedDate = item.LastUpdatedDate,
						SenderAddress = item.SenderAddress,
						SenderName = item.SenderName,
						StatusCode = StatusCode.GetCode(item.StatusCode),
						StatusDescription = item.StatusDescription,
						SubscriberId = item.SubscriberId,
						SubscriberType = (SubscriberType)item.SubscriberType
					});
		}

		public IEnumerable<PushIdAndApplicationId> FindByIdsAndState(IEnumerable<string> ids, MessageState state)
		{
			return ObjectContext.DbPushRequestDetails
				.Include("Request")
				.Include("Request.Application")
				.Where((item) => item.MessageState == (short)state)
				.ContainsEx((item) => item.Request.PushId, ids)
				.Select((item) =>
					new PushIdAndApplicationId(
						item.Request.PushId,
						item.Request.Application.RimApplicationId));
		}

		public IEnumerable<PushRequestDetail> FindByStatusCode(StatusCode statusCode, int startIndex, int endIndex)
		{
			return ObjectContext.DbPushRequestDetails
				.Include("Request")
				.Where((item) => item.StatusCode == statusCode.Code)
				.Skip(startIndex)
				.Take(endIndex - startIndex + 1)
				.Select((item) =>
					new PushRequestDetail
					{
						Id = item.Request.PushId,
						Address = item.Address,
						CompletedDate = item.CompletedDate,
						CreatedDate = item.CreatedDate,
						MessageState = (MessageState)item.MessageState,
						ModifiedDate = item.LastUpdatedDate,
						SenderAddress = item.SenderAddress,
						SenderName = item.SenderName,
						StatusCode = StatusCode.GetCode(item.StatusCode),
						StatusDescription = item.StatusDescription,
						SubscriberId = item.SubscriberId,
						SubscriberType = (SubscriberType)item.SubscriberType
					});
		}

		public IEnumerable<PushRequestDetail> FindIncompleteByAppIdAndSubId(string applicationId, string subscriberId)
		{
			return ObjectContext.DbPushRequestDetails
				.Include("Request")
				.Include("Request.Application")
				.Where((item) => item.Request.Application.RimApplicationId == applicationId && item.SubscriberId == subscriberId)
				.Select((item) =>
					new PushRequestDetail
					{
						Id = item.Request.PushId,
						Address = item.Address,
						CompletedDate = item.CompletedDate,
						CreatedDate = item.CreatedDate,
						MessageState = (MessageState)item.MessageState,
						ModifiedDate = item.LastUpdatedDate,
						SenderAddress = item.SenderAddress,
						SenderName = item.SenderName,
						StatusCode = StatusCode.GetCode(item.StatusCode),
						StatusDescription = item.StatusDescription,
						SubscriberId = item.SubscriberId,
						SubscriberType = (SubscriberType)item.SubscriberType
					});
		}

		public int GetSizeByDateRange(DateTime fromDate, DateTime toDate)
		{
			return ObjectContext.DbPushRequestDetails
				.Count((item) => item.CreatedDate >= fromDate && item.CreatedDate <= toDate);
		}

		public void UpdatePushRequestDetail(PushRequestDetail pushRequestDetail)
		{
			UpdatePushRequestDetailCore(pushRequestDetail, false);
			ObjectContext.SaveChanges();
		}

		public void UpdatePushRequestDetails(IEnumerable<PushRequestDetail> pushRequestDetails)
		{
			foreach (var pushRequestDetail in pushRequestDetails)
			{
				UpdatePushRequestDetailCore(pushRequestDetail, false);
			}
			ObjectContext.SaveChanges();
		}

		public void UpdatePushRequestDetailsWithoutAddresses(IEnumerable<PushRequestDetail> pushRequestDetails)
		{
			foreach (var pushRequestDetail in pushRequestDetails)
			{
				UpdatePushRequestDetailCore(pushRequestDetail, true);
			}
			ObjectContext.SaveChanges();
		}

		#endregion
	}
}
